package com.qiniu.githubdata.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qiniu.githubdata.entity.*;
import com.qiniu.githubdata.entity.dto.DeveloperSearchResponse;
import com.qiniu.githubdata.entity.dto.NationCount;
import com.qiniu.githubdata.entity.enumEntity.TagType;
import com.qiniu.githubdata.mapper.ContributionMapper;
import com.qiniu.githubdata.mapper.DeveloperMapper;
import com.qiniu.githubdata.mapper.DeveloperTagMapper;
import com.qiniu.githubdata.mapper.TagMapper;
import com.qiniu.githubdata.entity.dto.DeveloperDetailResponse;
import com.qiniu.githubdata.utils.ContributionUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * @Author: mayixiang
 * @Date: 2024-10-29 22:17
 * @Description:
 */
@Service
public class DeveloperService extends ServiceImpl<DeveloperMapper, Developer> {
    @Autowired
    private TagMapper tagMapper;
    @Autowired
    private DeveloperTagMapper developerTagMapper;
    @Resource
    private ContributionMapper contributionMapper;
    @Resource
    private DeveloperMapper developerMapper;
    @Resource
    private RepositoryService repositoryService;
    @Resource
    private ContributionService contributionService;

    @Resource
    private TagService tagService;

    // 方法：快速给用户增加标签
    public void addTagToDeveloper(Long developerId, Tag tag) {
        String tagName = tag.getName();
        int tagType = tag.getType();
        // 检查标签是否存在
        LambdaQueryWrapper<Tag> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Tag::getName, tagName);
        Tag existingTag = tagMapper.selectOne(queryWrapper);
        if (existingTag == null) {
            // 标签不存在，创建新标签
            Tag newTag = new Tag();
            newTag.setName(tagName);
            newTag.setType(tagType);
            // 插入新标签
            tagMapper.insert(newTag);
            existingTag = newTag; // 使用新标签的对象
        }

        // 添加开发者与标签的关联
        DeveloperTag developerTag = new DeveloperTag();
        developerTag.setDeveloperId(developerId);
        developerTag.setTagId(existingTag.getId());
        developerTagMapper.insert(developerTag);
    }

    public List<Developer> searchDevelopers(String q, List<String> tags, String domain, String nation, String sortBy, int page, int pageSize) {
        QueryWrapper<Developer> queryWrapper = new QueryWrapper<>();
        if (tags != null) {
            for (String tag : tags) {
                // 获取标签 ID
                long tagId = tagService.getTagIdByTypeAndName(TagType.USER_DOMAIN.getType(), tag);
                // 查询 DeveloperTag 表
                QueryWrapper<DeveloperTag> developerTagQueryWrapper = new QueryWrapper<>();
                developerTagQueryWrapper.eq("tag_id", tagId);
                List<DeveloperTag> developerTags = developerTagMapper.selectList(developerTagQueryWrapper);
                // 获取 Developer ID
                List<Long> developerIds = developerTags.stream().map(DeveloperTag::getDeveloperId).collect(Collectors.toList());
                // 添加 Developer ID 到查询条件
                queryWrapper.in("id", developerIds);
            }
        }
        if (StringUtils.isNotBlank(q)) {
            queryWrapper.like("login", q).or().like("name", q);
        }
        // 领域搜索
        if (StringUtils.isNotBlank(domain)) {
            queryWrapper.like("domains", domain);
        }

        // 国家筛选
        if (StringUtils.isNotBlank(nation)) {
            queryWrapper.eq("nation", nation);
        }

        // 排序
        switch (sortBy) {
            case "contribution":
                queryWrapper.orderByDesc("repository_count");
                break;
            case "talent_rank":
            default:
                queryWrapper.orderByDesc("talent_rank");
        }

        // 分页
        Page<Developer> pageParam = new Page<>(page, pageSize);

        return baseMapper.selectPage(pageParam, queryWrapper).getRecords();
    }

    // 计算开发者的 TalentRank
    public double calculateTalentRank(Long developerId) {
        // 1. 获取开发者的所有贡献
        QueryWrapper<Contribution> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("developer_id", developerId);
        List<Contribution> contributions = contributionMapper.selectList(queryWrapper);
        double talentRank = 0;
        for (Contribution contribution : contributions) {
            // 计算贡献度
            double contributionScore = ContributionUtil.calculateContributionScore(contribution);
            // 计算项目重要度

            double repoId = contribution.getRepositoryId();
            // 从数据库中获取项目重要度
            double projectImportance = repositoryService.getImportance(repositoryService.getById(repoId));
            // 计算最终分数
            talentRank += contributionScore * projectImportance;
        }

        return talentRank;
    }
    public Developer updateTalentRank(Long developerId) {
        double talentRank = calculateTalentRank(developerId);
        Developer developer = baseMapper.selectById(developerId);
        developer.setTalentRank(talentRank);
        baseMapper.updateById(developer);
        return developer;
    }

    public Developer getDeveloperByLogin(String login) {
        QueryWrapper<Developer> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("login", login);
        return baseMapper.selectOne(queryWrapper);
    }

    public List<Long> getDeveloperIdsByTagNameDomain(String tagName) {
        long id = tagService.getTagIdByTypeAndName(TagType.USER_DOMAIN.getType(), tagName);
        QueryWrapper<DeveloperTag> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("tag_id", id);
        List<DeveloperTag> developerTags = developerTagMapper.selectList(queryWrapper);
        return developerTags.stream().map(DeveloperTag::getDeveloperId).collect(Collectors.toList());
    }

    public DeveloperDetailResponse getDeveloperDetail(Long developerId) {
        Developer developer = baseMapper.selectById(developerId);
        if (developer == null) {
            return null;
        }
        DeveloperDetailResponse response = new DeveloperDetailResponse();
        convertDeveloperToDetail(developer, response);
        return response;
    }

    public  void convertDeveloperToDetail(Developer developer, DeveloperDetailResponse response) {
        long developerId = developer.getId();
        response.setId(developer.getId());
        response.setLogin(developer.getLogin());
        response.setUsername(developer.getUserName());
        response.setAvatarUrl(developer.getAvatarUrl());
        response.setGithubUrl(developer.getGithubUrl());
        response.setTalentRank(developer.getTalentRank());
        response.setNation(developer.getNation());
        response.setIsEstimate(developer.isEstimated());
        response.setNationConfidence(developer.getNationConfidence());
//        response.setDomain(developer.getDomains());
        response.setSummary(developer.getEvaluationInfo());
        response.setBio(developer.getBio());
        response.setBlog(developer.getBlog());
        List<Repository> repositories = getDeveloperTop10Repositories(developer);
        List<String> tags = tagService.getTagsByDeveloperId(developerId);
        response.setDomain(tags);
//        response.setRepositories(repositories);
        response.setRepositoryCount(repositories.size());
    }

    public List<Repository>
    getDeveloperTop10Repositories(Developer developer) {
        QueryWrapper<Repository> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("owner", developer.getLogin());
        queryWrapper.orderByDesc("importance");
        queryWrapper.last("limit 10");
        List<Repository> repositories = repositoryService.list(queryWrapper);
        return repositories;
    }
    public void convertDeveloperToSearch(Developer developer, DeveloperSearchResponse response) {
        response.setId(developer.getId());
        response.setLogin(developer.getLogin());
        response.setAvatarUrl(developer.getAvatarUrl());
        response.setUserName(developer.getUserName());
        // response.setTalentRank(developer.getTalentRank());
        response.setNation(developer.getNation());
        response.setEstimated(developer.isEstimated());
        response.setNationConfidence(developer.getNationConfidence());
        // response.setDomain(developer.getDomains());
        // response.setGithubUrl(developer.getGithubUrl());
        // response.setSummary(developer.getEvaluationInfo());
    }

    public List<DeveloperSearchResponse> searchResponse(String q, int page, int pageSize) {
        //Tom language:Java location:china languages:c
        List<DeveloperSearchResponse> response = new ArrayList<>();
        if (q == null || q.trim().isEmpty()) {
            return response;
        }

        // Pattern for extracting components:
        // language:xxx - programming language filter
        // location:xxx - location filter
        Pattern languagePattern = Pattern.compile("language:(\\w+)");
        Pattern locationPattern = Pattern.compile("location:(\\w+)");

        Matcher languageMatcher = languagePattern.matcher(q);
        Matcher locationMatcher = locationPattern.matcher(q);

        String language = languageMatcher.find() ? languageMatcher.group(1) : null;
        String location = locationMatcher.find() ? locationMatcher.group(1) : null;
        //获取除了tag外的信息：如Tom language:Java location:china languages:c 中获取tom
        String baseQuery = q.replaceAll("language:\\w+", "")
                           .replaceAll("location:\\w+", "")
                           .trim();
        List<Long> developerIds = tagService.getDeveloperIdsByDeveloperTag(language, location);
        List<Long> baseDeveloperIds = new ArrayList<>();
        if(StringUtils.isNotEmpty(baseQuery)){
            baseDeveloperIds = developerMapper.searchByName(baseQuery);
        }
        // 取交集
        if(developerIds==null||developerIds.isEmpty()) {
            developerIds = baseDeveloperIds;
        } else {
            developerIds.retainAll(baseDeveloperIds);
        }
        // 分页
        int start = (page - 1) * pageSize;
        int end = Math.min(start + pageSize, developerIds.size());
        developerIds = developerIds.subList(start, end);
        // 根据developerIds 和q 查询开发者
        List<Developer> developers = new ArrayList<>();
        if (!developerIds.isEmpty()) {
            developers = baseMapper.selectBatchIds(developerIds);
        }
        for (Developer developer : developers) {
            DeveloperSearchResponse searchResponse = new DeveloperSearchResponse();
            convertDeveloperToSearch(developer, searchResponse);
            response.add(searchResponse);
        }

        return response;
    }
public String guessNationByFollowers(Long developerId) {
    // 获取所有关注者的国家信息
    List<NationCount> directFollowerNations = developerMapper.getFollowersNationCount(developerId);

    // 获取二级关注者的国家分布（关注者的关注者）
    List<NationCount> indirectFollowerNations = developerMapper.getSecondLevelFollowersNationCount(developerId);

    if (directFollowerNations.isEmpty() && indirectFollowerNations.isEmpty()) {
        return null;
    }

    // 合并两级关注者的国家分布，直接关注者权重更高
    Map<String, Double> weightedNationCounts = new HashMap<>();

    // 处理直接关注者，权重为1.0
    processNationCounts(directFollowerNations, weightedNationCounts, 1.0);

    // 处理间接关注者，权重为0.5
    processNationCounts(indirectFollowerNations, weightedNationCounts, 0.5);

    // 找出加权后最高的国家
    Map.Entry<String, Double> mostCommon = Collections.max(
            weightedNationCounts.entrySet(),
            Map.Entry.comparingByValue()
    );

    // 计算置信度
    double confidence = calculateEnhancedConfidence(
            mostCommon.getValue(),
            weightedNationCounts.values().stream().mapToDouble(Double::doubleValue).sum(),
            weightedNationCounts.size(),
            directFollowerNations.size(),
            indirectFollowerNations.size()
    );

    // 更新开发者信息
    Developer developer = this.getById(developerId);
    developer.setNation(mostCommon.getKey());
    developer.setNationConfidence((int)(confidence * 100));
    developer.setEstimated(true);
    this.updateById(developer);

    return mostCommon.getKey();
}

private double calculateConfidence(int dominantCount, int totalCount, int uniqueNations) {
    // 基础置信度：主导国家的占比
    double baseConfidence = (double) dominantCount / totalCount;
    // 多样性惩罚：国家越多，置信度越低
    double diversityPenalty = Math.log(uniqueNations) / Math.log(totalCount);
    // 样本量奖励：关注者越多，置信度越高
    double sampleBonus = Math.min(1.0, Math.log(totalCount) / Math.log(100));
    return baseConfidence * (1 - diversityPenalty) * sampleBonus;
}
private void processNationCounts(List<NationCount> nationCounts, 
                               Map<String, Double> weightedNationCounts, 
                               double weight) {
    for (NationCount nc : nationCounts) {
        weightedNationCounts.merge(
            nc.getNation(), 
            nc.getCount() * weight,
            Double::sum
        );
    }
}

private double calculateEnhancedConfidence(double dominantCount, 
                                         double totalCount,
                                         int uniqueNations,
                                         int directFollowersCount,
                                         int indirectFollowersCount) {
    // 基础置信度：主导国家的占比
    double baseConfidence = dominantCount / totalCount;
    
    // 多样性惩罚：国家种类越多，置信度越低
    double diversityPenalty = Math.log(uniqueNations + 1) / Math.log(totalCount + 1);
    
    // 样本量奖励：关注者越多，置信度越高，但有上限
    double sampleBonus = Math.min(1.0, 
        (Math.log(directFollowersCount + 1) + 0.5 * Math.log(indirectFollowersCount + 1)) 
        / Math.log(100));
    
    // 关注者质量奖励：直接关注者比例越高，置信度越高
    double qualityBonus = (double) directFollowersCount / 
        (directFollowersCount + indirectFollowersCount);
    
    return baseConfidence * (1 - diversityPenalty) * sampleBonus * (1 + 0.2 * qualityBonus);
}
}

